package com.example.demo.service.impl;

import com.example.demo.domain.vo.GroupVO;
import com.example.demo.domain.vo.HistoricIdentityLinkVO;
import com.example.demo.domain.vo.HistoricProcessInstanceVo;
import com.example.demo.domain.vo.HistoryTaskInstanceVo;
import com.example.demo.domain.vo.IdentityLinkVo;
import com.example.demo.domain.vo.ProcessInstanceVo;
import com.example.demo.domain.vo.TaskVo;
import com.example.demo.domain.vo.UserVO;
import com.example.demo.service.ActivitiService;
import com.example.demo.utils.ActivitiUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricIdentityLink;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;


/**
 *
 * @Description: activiti的基础api的使用
 * @Author: zsg
 * @Date: 2018/07/02 15:26
 */
@Service
@Transactional
public class ActivitiServiceImpl implements ActivitiService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private ProcessEngine processEngine;
    /**
     * 创建用户
     * @param userVO
     */
    @Override
    public void createUser(UserVO userVO) {
        User newUser = this.identityService.newUser(userVO.getId());
        newUser.setEmail(userVO.getEmail());
        newUser.setFirstName(userVO.getFirstName());
        newUser.setLastName(userVO.getLastName());
        newUser.setPassword(userVO.getPassword());

       this.identityService.saveUser(newUser);
    }

    /**
     * 创建角色
     * @param groupVO
     */
    @Override
    public void createGroup(GroupVO groupVO) {
        Group group = this.identityService.newGroup(groupVO.getId());
        group.setName(groupVO.getName());
        group.setType(groupVO.getType());
        this.identityService.saveGroup(group);
    }

    /**
     * 关联关系
     * @param uid
     * @param gid
     */
    @Override
    public void createMemberShip(String uid, String gid) {
        this.identityService.createMembership(uid,gid);
    }

    /**
     * 开始一个任务
     * @param processKey
     * @param userId  流程发起者
     */
    @Override
    public List<ProcessInstanceVo> startProcess(String processKey, String userId) {
        //记录流程的发起人
        identityService.setAuthenticatedUserId(userId);
        //开始流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey);

        System.out.println("流程id为"+processInstance.getId());

        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();

        List<ProcessInstanceVo> processInstanceVOList = new ArrayList<>();

        list.forEach(task -> {
            ProcessInstanceVo processInstanceVO = new ProcessInstanceVo();
            processInstanceVO.setDeploymentId(processInstance.getDeploymentId());
            processInstanceVO.setId(processInstance.getId());
            processInstanceVO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
            processInstanceVO.setName(processInstance.getName());
            processInstanceVO.setActivityId(processInstance.getActivityId());
            processInstanceVO.setProcessDefinitionName(processInstance.getProcessDefinitionName());
            processInstanceVO.setTaskId(task.getId());
            processInstanceVO.setTaskName(task.getName());
            processInstanceVOList.add(processInstanceVO);
        });

        return processInstanceVOList;
    }

    /**
     * 开启一个组任务
     * @param processKey
     * @param userIds
     * @return
     */
    @Override
    public ProcessInstanceVo startGroupProcess(String processKey, String userIds) {
        Map<String,Object> variables = new HashMap<>();
        variables.put("userIds",userIds);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, variables);
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

        ProcessInstanceVo processInstanceVO = new ProcessInstanceVo();
        processInstanceVO.setDeploymentId(processInstance.getDeploymentId());
        processInstanceVO.setId(processInstance.getId());
        processInstanceVO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        processInstanceVO.setName(processInstance.getName());
        processInstanceVO.setActivityId(processInstance.getActivityId());
        processInstanceVO.setProcessDefinitionName(processInstance.getProcessDefinitionName());
        processInstanceVO.setTaskId(task.getId());
        processInstanceVO.setTaskName(task.getName());

        return processInstanceVO;
    }

    /**
     * 获得某个人的任务别表
     * @param assignee 名称
     * @return
     */
    @Override
    public List<TaskVo> findMyTaskList(String assignee) {

        List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned(assignee).list();

        List<TaskVo> taskVoList = new ArrayList<>();

        list.forEach(task -> {
            TaskVo taskVo = new TaskVo();
            taskVo.setAssignee(task.getAssignee());
            taskVo.setExecutionId(task.getExecutionId());
            taskVo.setId(task.getId());
            taskVo.setName(task.getName());
            taskVo.setProcessDefinitionId(task.getProcessDefinitionId());
            taskVo.setProcessInstanceId(task.getProcessInstanceId());
            taskVoList.add(taskVo);
        });
        return taskVoList;
    }

    /**
     * 按照任务Id完成对应的任务
     * @param taskId 任务Id
     */
    @Override
    public void competeCurrentTask(String taskId) {
        taskService.complete(taskId);
    }

    /**
     * 完成委托任务
     * @param taskId
     */
    @Override
    public void completeOwnerTask(String taskId) {
        taskService.resolveTask(taskId);
    }

    /**
     * 委托任务
     * @param taskId
     * @param userId
     */
    @Override
    public void ownerTask(String taskId,String userId) {
        taskService.delegateTask(taskId, userId);
    }


    /**
     * 按照执行人查看历史任务
     * @param taskAssignee
     * @return
     */
    @Override
    public List<HistoryTaskInstanceVo> findHistoryTask(String taskAssignee) {
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().taskAssignee(taskAssignee).list();
        List<HistoryTaskInstanceVo> taskInstanceVoList = new ArrayList<>();
        list.forEach(historicTaskInstance -> {
            HistoryTaskInstanceVo historyTaskInstanceVo = new HistoryTaskInstanceVo();
            historyTaskInstanceVo.setStartTime(historicTaskInstance.getStartTime());
            historyTaskInstanceVo.setEndTime(historicTaskInstance.getEndTime());
            historyTaskInstanceVo.setAssignee(historicTaskInstance.getAssignee());
            historyTaskInstanceVo.setId(historicTaskInstance.getId());
            historyTaskInstanceVo.setName(historicTaskInstance.getName());
            historyTaskInstanceVo.setProcessInstanceId(historicTaskInstance.getProcessInstanceId());
            historyTaskInstanceVo.setProcessDefinitionId(historicTaskInstance.getProcessDefinitionId());
            taskInstanceVoList.add(historyTaskInstanceVo);

        });
        return taskInstanceVoList;
    }

    /**
     * 查询历史流程
     * @return
     */
    @Override
    public HistoricProcessInstanceVo findHistoryProcessInstance(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService//与历史数据（历史表）相关的Service
                .createHistoricProcessInstanceQuery()//创建历史流程实例查询
                .processInstanceId(processInstanceId)//使用流程实例ID查询
                .singleResult();

        HistoricProcessInstanceVo historicProcessInstanceVO = new HistoricProcessInstanceVo();

        historicProcessInstanceVO.setBusinessKey(historicProcessInstance.getBusinessKey());
        historicProcessInstanceVO.setDeleteReason(historicProcessInstance.getDeleteReason());
        historicProcessInstanceVO.setDeploymentId(historicProcessInstance.getDeploymentId());
        historicProcessInstanceVO.setEndTime(historicProcessInstance.getEndTime());
        historicProcessInstanceVO.setId(historicProcessInstance.getId());
        historicProcessInstanceVO.setName(historicProcessInstance.getName());
        historicProcessInstanceVO.setProcessDefinitionId(historicProcessInstance.getProcessDefinitionId());
        historicProcessInstanceVO.setProcessDefinitionKey(historicProcessInstance.getProcessDefinitionKey());
        historicProcessInstanceVO.setProcessDefinitionName(historicProcessInstance.getProcessDefinitionName());
        historicProcessInstanceVO.setProcessDefinitionVersion(historicProcessInstance.getProcessDefinitionVersion());
        historicProcessInstanceVO.setStartActivityId(historicProcessInstance.getStartActivityId());
        historicProcessInstanceVO.setSuperProcessInstanceId(historicProcessInstance.getSuperProcessInstanceId());
        historicProcessInstanceVO.setStartTime(historicProcessInstance.getStartTime());
        historicProcessInstanceVO.setTenantId(historicProcessInstance.getTenantId());
        historicProcessInstanceVO.setStartUserId(historicProcessInstance.getStartUserId());

        return historicProcessInstanceVO;
    }

    /**
     * 获取流程图
     * @param deploymentId
     */
    @Override
    public void viewPic(String deploymentId) {
        List<String> list = this.repositoryService.getDeploymentResourceNames(deploymentId);

        //定义图片资源的名称
        String resourceName = "";
        if(list!=null && list.size()>0){
            for(String name:list){
                if(name.indexOf(".png")>=0){
                    resourceName = name;
                }
            }
        }

        //获取图片的输入流
        InputStream in =  getDiagram(deploymentId);

        //将图片生成到D盘的目录下
        File file = new File(resourceName);
        //将输入流的图片写到D盘下
        try {
            FileUtils.copyInputStreamToFile(in, file);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 结束流程
     * @param processInstanceId
     * @param reason  结束的原因
     */
    @Override
    public void deleteProcess(String processInstanceId,String reason) {
        this.runtimeService.deleteProcessInstance(processInstanceId,reason);
    }

    /**
     * 添加组任务的成员
     * @param taskId
     * @param userId
     */
    @Override
    public void addGroupUser(String taskId, String userId) {
        this.taskService.addCandidateUser(taskId,userId);
    }

    /**
     * 删除组任务的成员
     * @param taskId
     * @param userId
     */
    @Override
    public void deleteGroupUser(String taskId, String userId) {
        taskService.deleteCandidateUser(taskId,userId);
    }

    /**
     * 拾取任务（指定组任务到个人）
     * @param taskId
     * @param userId
     */
    @Override
    public void claim(String taskId, String userId) {
        taskService.claim(taskId,userId);
    }

    /**
     * 查询组任务成员历史列表
     * @param taskId
     * @return
     */
    @Override
    public List<HistoricIdentityLinkVO> findHistoryGroupUser(String taskId) {
        List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(taskId);
        List<HistoricIdentityLinkVO> historicIdentityLinkVOList = new ArrayList<>();

        linksForTask.forEach(historicIdentityLink -> {
            HistoricIdentityLinkVO historicIdentityLinkVO = new HistoricIdentityLinkVO();

            historicIdentityLinkVO.setGroupId(historicIdentityLink.getGroupId());
            historicIdentityLinkVO.setTaskId(historicIdentityLink.getTaskId());
            historicIdentityLinkVO.setProcessInstanceId(historicIdentityLink.getProcessInstanceId());
            historicIdentityLinkVO.setType(historicIdentityLink.getType());
            historicIdentityLinkVO.setUserId(historicIdentityLink.getUserId());

            historicIdentityLinkVOList.add(historicIdentityLinkVO);
        });

        return historicIdentityLinkVOList;
    }


    /**
     * 查询组的用户
     * @param taskId
     * @return
     */
    @Override
    public List<IdentityLinkVo> findGroupUser(String taskId) {
        List<IdentityLink> linksForTask = taskService.getIdentityLinksForTask(taskId);

        List<IdentityLinkVo> linkVoList = new ArrayList<>();

        linksForTask.forEach(identityLink -> {
            IdentityLinkVo identityLinkVO = new IdentityLinkVo();

            identityLinkVO.setGroupId(identityLink.getGroupId());
            identityLinkVO.setType(identityLink.getType());
            identityLinkVO.setProcessDefinitionId(identityLink.getProcessDefinitionId());
            identityLinkVO.setProcessInstanceId(identityLink.getProcessInstanceId());
            identityLinkVO.setUserId(identityLink.getUserId());
            identityLinkVO.setTaskId(identityLink.getTaskId());

            linkVoList.add(identityLinkVO);
        });
        return linkVoList;
    }

    /**
     *查询用户的组任务
     * @param userId
     * @return
     */
    @Override
    public List<TaskVo> findMyGroupTask(String userId) {

        List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userId).list();

        List<TaskVo> taskVoList = new ArrayList<>();

        taskList.forEach(task -> {
            TaskVo taskVo = new TaskVo();
            taskVo.setAssignee(task.getAssignee());
            taskVo.setExecutionId(task.getExecutionId());
            taskVo.setId(task.getId());
            taskVo.setName(task.getName());
            taskVo.setProcessDefinitionId(task.getProcessDefinitionId());
            taskVo.setProcessInstanceId(task.getProcessInstanceId());
            if (!group(task.getProcessInstanceId(),task.getId(),userId)){
                taskVoList.add(taskVo);
            }
        });

        return taskVoList;
    }

    private  boolean group(String processInstanceId,String taskId,String userId){
        List<String> group = new ArrayList<>();
        AtomicBoolean flag = new AtomicBoolean(false);
        historyService.createHistoricActivityInstanceQuery().taskAssignee(userId).processInstanceId(processInstanceId).list().forEach(historicActivityInstance -> {

            ActivitiUtils activitiUtils = new ActivitiUtils();
            try {
                List<String> nextTaskGroup = activitiUtils.getNextTaskGroup(taskId);
                nextTaskGroup.forEach(s -> {
                    if(historicActivityInstance.getActivityId().equals(s)){
                        flag.set(true);
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return flag.get();
    }

    /**
     * 开启一个排他网关的流程
     * @param processKey
     * @param money 条件
     * @return
     */
    @Override
    public ProcessInstanceVo startExclusiveGateWayProcess(String processKey, double money) {
        Map<String,Object> variables = new HashMap<>();
        variables.put("money",money);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, variables);
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

        ProcessInstanceVo processInstanceVO = new ProcessInstanceVo();
        processInstanceVO.setDeploymentId(processInstance.getDeploymentId());
        processInstanceVO.setId(processInstance.getId());
        processInstanceVO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
        processInstanceVO.setName(processInstance.getName());
        processInstanceVO.setActivityId(processInstance.getActivityId());
        processInstanceVO.setProcessDefinitionName(processInstance.getProcessDefinitionName());
        processInstanceVO.setTaskId(task.getId());
        processInstanceVO.setTaskName(task.getName());
        return processInstanceVO;
    }

    /**
     * 开启一个并行网关流程
     * @param processKey
     * @return
     */
    @Override
    public List<ProcessInstanceVo> startparallelGateWayProcess(String processKey) {

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey);
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();

        List<ProcessInstanceVo> processInstanceVOList = new ArrayList<>();

        list.forEach(task -> {
            ProcessInstanceVo processInstanceVO = new ProcessInstanceVo();
            processInstanceVO.setDeploymentId(processInstance.getDeploymentId());
            processInstanceVO.setId(processInstance.getId());
            processInstanceVO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
            processInstanceVO.setName(processInstance.getName());
            processInstanceVO.setActivityId(processInstance.getActivityId());
            processInstanceVO.setProcessDefinitionName(processInstance.getProcessDefinitionName());
            processInstanceVO.setTaskId(task.getId());
            processInstanceVO.setTaskName(task.getName());
            processInstanceVOList.add(processInstanceVO);
        });

        return processInstanceVOList;
    }


    /**
     * 获取流程图的对应节点图
     * @param processInstanceId
     * @return
     */
    public InputStream getDiagram(String processInstanceId) {
        //获得流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = StringUtils.EMPTY;
        if (processInstance == null) {
            //查询已经结束的流程实例
            HistoricProcessInstance processInstanceHistory = historyService.createHistoricProcessInstanceQuery()
                                                     .processInstanceId(processInstanceId).singleResult();
            if (processInstanceHistory == null) {
                return null;
            }else {
                processDefinitionId = processInstanceHistory.getProcessDefinitionId();
            }

        } else {
            processDefinitionId = processInstance.getProcessDefinitionId();
        }

        //使用宋体
        String fontName = "宋体";
        //获取BPMN模型对象
        BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
        //获取流程实例当前的节点，需要高亮显示
        List<String> currentActs = Collections.EMPTY_LIST;
        if (processInstance != null)
            currentActs = runtimeService.getActiveActivityIds(processInstance.getId());
        return processEngine.getProcessEngineConfiguration()
                .getProcessDiagramGenerator()
                .generateDiagram(model, "png", currentActs, new ArrayList<String>(),
                        fontName, fontName, fontName, null, 1.0);
    }


}
